package com.mtr.databoard.domain.middlewares;

import com.mtr.databoard.common.linqlist.LinqList;
import com.mtr.databoard.domain.components.ViewComponent;
import com.mtr.databoard.domain.components.ViewResource;
import com.mtr.databoard.domain.resources.ContextResource;
import com.mtr.databoard.domain.resources.FileContent;
import com.mtr.databoard.domain.resources.ResourceEntity;
import com.mtr.databoard.domain.resources.ResourceStore;
import com.mtr.sdk.IMiddleware;
import org.bson.types.Binary;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;


@Component
public class MiddlewareManager {
    private IMiddlewareRepository middlewareRepository;
    private ResourceStore resourceStore;

    public MiddlewareManager(@Autowired IMiddlewareRepository middlewareRepository, @Autowired ResourceStore resourceStore) {
        this.middlewareRepository = middlewareRepository;
        this.resourceStore = resourceStore;
    }

    /**
     * 创建
     *
     * @param cover
     * @param name
     * @param description
     * @param middlewareResource
     * @param updateFrequency
     * @param parameters
     * @param isPush
     * @return
     */
    public Middleware create(MiddlewareResource cover, String name, String description, MiddlewareResource middlewareResource, String middlewareEntry, long updateFrequency, List<Parameter> parameters, boolean isPush) throws IOException {
        Middleware middleware = new Middleware(cover, name, description, middlewareResource, middlewareEntry, updateFrequency, parameters, isPush);
        ResourceEntity currentEntity = new ResourceEntity(Middleware.class.getName(), middleware.getId().toString());

        var contextResources = new ArrayList<ContextResource>();
        //绑定封面文件
        if (middleware.getCover() != null) {
            resourceStore.bindEntity(middleware.getCover().getFileId(), currentEntity);
            contextResources.add(new ContextResource(middleware.getCover().getFileId(), middleware.getCover().getFileName()));
        }
        //绑定中间件文件
        if (middleware.getMiddleware() != null) {
            resourceStore.bindEntity(middleware.getMiddleware().getFileId(), currentEntity);
            contextResources.add(new ContextResource(middleware.getMiddleware().getFileId(), middleware.getMiddleware().getFileName()));
        }
        middlewareRepository.insert(middleware);

        //重新释放资源
        resourceStore.releaseResources(contextResources, "middleware", middleware.getId().toString(), true);

        return middleware;
    }

    /**
     * 、更新
     *
     * @param middlewareId
     * @param cover
     * @param name
     * @param description
     * @param middlewareResource
     * @param updateFrequency
     * @param parameters
     * @param isPush
     */
    public void update(UUID middlewareId, MiddlewareResource cover, String name, String description, MiddlewareResource middlewareResource, String middlewareEntry, long updateFrequency, List<Parameter> parameters, boolean isPush) throws IOException {
        if (!middlewareRepository.existsById(middlewareId)) return;
        Middleware middleware = middlewareRepository.findById(middlewareId).get();
        ResourceEntity resourceEntity = new ResourceEntity(Middleware.class.getName(), middleware.getId().toString());

        var oldContextResources = new ArrayList<ContextResource>();
        if(middleware.getMiddleware() != null)
            oldContextResources.add(new ContextResource(middleware.getMiddleware().getFileId(),middleware.getMiddleware().getFileName()));
        if(middleware.getCover()!= null )
            oldContextResources.add(new ContextResource(middleware.getCover().getFileId(),middleware.getCover().getFileName()));
        var linqOldres = new LinqList<>(oldContextResources);
        var newContextResources = new ArrayList<ContextResource>();
        if(middlewareResource != null)
            newContextResources.add(new ContextResource(middlewareResource.getFileId(),middlewareResource.getFileName()));
        if(cover != null)
            newContextResources.add(new ContextResource(cover.getFileId(),cover.getFileName()));

        var linqNewres = new LinqList<>(newContextResources);

        for (var oldResource : oldContextResources) {
            //新的不包含则解绑
            if (linqNewres.count(r -> r.getFileId()!=null&&r.getFileId().equals(oldResource.getFileId())) == 0)
                resourceStore.unbindEntity(oldResource.getFileId(), resourceEntity);

        }

        for (var newResource : newContextResources) {
            //旧的不包含则加绑
            if (linqOldres.count(r ->r.getFileId()!=null&& r.getFileId().equals(newResource.getFileId())) == 0)
                resourceStore.bindEntity(newResource.getFileId(), resourceEntity);
        }

        middleware.update(cover, name, description, middlewareResource, middlewareEntry, updateFrequency, parameters, isPush);
        //重新释放资源
        resourceStore.releaseResources(newContextResources, "middleware", middleware.getId().toString(), true);
        middlewareRepository.save(middleware);
    }

    /**
     * 删除
     *
     * @param middlewareId
     */
    public void delete(UUID middlewareId) {
        if (!middlewareRepository.existsById(middlewareId)) return;
        Middleware middleware = middlewareRepository.findById(middlewareId).get();

        ResourceEntity currentEntity = new ResourceEntity(Middleware.class.getName(), middleware.getId().toString());

        //解除绑定封面文件
        if (middleware.getCover() != null) {
            resourceStore.unbindEntity(middleware.getCover().getFileId(), currentEntity);
        }
        //解除绑定中间件文件
        if (middleware.getMiddleware() != null) {
            resourceStore.unbindEntity(middleware.getMiddleware().getFileId(), currentEntity);
        }
        middlewareRepository.deleteById(middlewareId);
        //清除释放的资源
        resourceStore.clearReleasedResources("middleware", middlewareId.toString());
    }

    /**
     * 复制中间间
     * @param middleareId
     * @return
     * @throws IOException
     * @throws CloneNotSupportedException
     */
    public Middleware copy(UUID middleareId) throws IOException, CloneNotSupportedException {
        Middleware middleware = middlewareRepository.findById(middleareId).get();
        middleware = middleware.copy();
        ResourceEntity currentEntity = new ResourceEntity(Middleware.class.getName(), middleware.getId().toString());

        var contextResources = new ArrayList<ContextResource>();
        //绑定封面文件
        if (middleware.getCover() != null) {
            resourceStore.bindEntity(middleware.getCover().getFileId(), currentEntity);
            contextResources.add(new ContextResource(middleware.getCover().getFileId(), middleware.getCover().getFileName()));
        }
        //绑定中间件文件
        if (middleware.getMiddleware() != null) {
            resourceStore.bindEntity(middleware.getMiddleware().getFileId(), currentEntity);
            contextResources.add(new ContextResource(middleware.getMiddleware().getFileId(), middleware.getMiddleware().getFileName()));
        }
        middlewareRepository.insert(middleware);

        //重新释放资源
        resourceStore.releaseResources(contextResources, "middleware", middleware.getId().toString(), true);

        return middleware;
    }

    /**
     * 执行中间件
     *
     * @param middlewareId
     * @param parameters
     * @return
     */
    public Object execute(UUID middlewareId, List<Parameter> parameters) {
        if (!middlewareRepository.existsById(middlewareId)) return null;
        Middleware middleware = middlewareRepository.findById(middlewareId).get();
        if (middleware.getMiddleware() == null) return null;
        var middlewareResource = middleware.getMiddleware();
        var middlewareFilePath = resourceStore.getFilePath("middleware", middlewareId.toString(), middlewareResource.getFileName());
        try {
            var url = new URL("file:" + middlewareFilePath);
            URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{url}, Thread.currentThread().getContextClassLoader());
            Class<?> middlewareClass = null;
            middlewareClass = urlClassLoader.loadClass(middleware.getMiddlewareEntry());
            IMiddleware iMiddleware = (IMiddleware) middlewareClass.getDeclaredConstructor().newInstance();
            List<com.mtr.sdk.Parameter> sdkParameters = new ArrayList<>();
            if (parameters != null) {
                for (Parameter parameter : parameters) {
                    sdkParameters.add(new com.mtr.sdk.Parameter(parameter.getName(), parameter.getValue()));
                }
            }

            var value = iMiddleware.Execute(sdkParameters);
            urlClassLoader.close();
            return  value;
        } catch (ClassNotFoundException | NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }
}
